import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
import { createTestingModule } from './setup';
import { Repository } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from '../src/database/entities/user.entity';
import { Role } from '../src/database/entities/role.entity';
import { UserRole } from '../src/database/entities/user-role.entity';
import * as bcrypt from 'bcrypt';

describe('UsersController (e2e)', () => {
  let app: INestApplication;
  let userRepository: Repository<User>;
  let roleRepository: Repository<Role>;
  let userRoleRepository: Repository<UserRole>;
  let adminToken: string;
  let adminUser: User;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await createTestingModule([
      AppModule,
    ]);

    app = moduleFixture.createNestApplication();
    await app.init();

    userRepository = moduleFixture.get<Repository<User>>(getRepositoryToken(User));
    roleRepository = moduleFixture.get<Repository<Role>>(getRepositoryToken(Role));
    userRoleRepository = moduleFixture.get<Repository<UserRole>>(getRepositoryToken(UserRole));

    // 创建角色
    const adminRole = roleRepository.create({
      name: 'admin',
      code: 'admin',
      description: '系统管理员',
      status: 1,
      sort: 0,
    });

    const userRole = roleRepository.create({
      name: 'user',
      code: 'user',
      description: '普通用户',
      status: 1,
      sort: 1,
    });

    await roleRepository.save([adminRole, userRole]);

    // 创建管理员用户
    adminUser = userRepository.create({
      username: 'admin',
      email: 'admin@example.com',
      password: await bcrypt.hash('admin123', 12),
      nickname: 'Administrator',
      phone: '13800138000',
      status: 1,
    });
    await userRepository.save(adminUser);

    // 分配管理员角色
    const adminUserRole = userRoleRepository.create({
      userId: adminUser.id,
      roleId: adminRole.id,
    });
    await userRoleRepository.save(adminUserRole);

    // 登录获取管理员token
    const loginResponse = await request(app.getHttpServer())
      .post('/api/auth/login')
      .send({ username: 'admin', password: 'admin123' });

    adminToken = loginResponse.body.access_token;
  });

  afterEach(async () => {
    await app.close();
  });

  describe('/api/users (GET)', () => {
    it('should get users list with pagination', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/users?page=1&limit=10')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body).toMatchObject({
        data: expect.any(Array),
        total: expect.any(Number),
        page: 1,
        limit: 10,
      });

      expect(response.body.data.length).toBeGreaterThan(0);
      expect(response.body.data[0]).not.toHaveProperty('password');
    });

    it('should filter users by username', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/users?username=admin')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body.data).toHaveLength(1);
      expect(response.body.data[0].username).toBe('admin');
    });

    it('should return 401 without token', async () => {
      await request(app.getHttpServer())
        .get('/api/users')
        .expect(401);
    });
  });

  describe('/api/users (POST)', () => {
    const createUserDto = {
      username: 'newuser',
      email: 'new@example.com',
      password: 'password123',
      nickname: 'New User',
      phone: '13800138001',
      roleIds: [2],
    };

    it('should create a new user successfully', async () => {
      const response = await request(app.getHttpServer())
        .post('/api/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(createUserDto)
        .expect(201);

      expect(response.body).toMatchObject({
        id: expect.any(Number),
        username: createUserDto.username,
        email: createUserDto.email,
        nickname: createUserDto.nickname,
        phone: createUserDto.phone,
      });

      expect(response.body).not.toHaveProperty('password');
    });

    it('should return 409 when username already exists', async () => {
      const duplicateDto = {
        ...createUserDto,
        username: 'admin', // 使用已存在的用户名
        email: 'different@example.com',
      };

      const response = await request(app.getHttpServer())
        .post('/api/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(duplicateDto)
        .expect(409);

      expect(response.body.message).toContain('用户名已存在');
    });

    it('should return 400 with invalid data', async () => {
      const invalidDto = {
        username: '', // 空用户名
        email: 'invalid-email', // 无效邮箱
        password: '123', // 密码太短
      };

      await request(app.getHttpServer())
        .post('/api/users')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(invalidDto)
        .expect(400);
    });
  });

  describe('/api/users/:id (GET)', () => {
    let testUser: User;

    beforeEach(async () => {
      testUser = userRepository.create({
        username: 'testuser',
        email: 'test@example.com',
        password: await bcrypt.hash('password123', 12),
        nickname: 'Test User',
        phone: '13800138002',
        status: 1,
      });
      await userRepository.save(testUser);
    });

    it('should get user by id successfully', async () => {
      const response = await request(app.getHttpServer())
        .get(`/api/users/${testUser.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      expect(response.body).toMatchObject({
        id: testUser.id,
        username: testUser.username,
        email: testUser.email,
        nickname: testUser.nickname,
        userRoles: expect.any(Array),
      });

      expect(response.body).not.toHaveProperty('password');
    });

    it('should return 404 when user not found', async () => {
      const response = await request(app.getHttpServer())
        .get('/api/users/999')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

      expect(response.body.message).toBe('用户不存在');
    });
  });

  describe('/api/users/:id (PUT)', () => {
    let testUser: User;

    beforeEach(async () => {
      testUser = userRepository.create({
        username: 'testuser',
        email: 'test@example.com',
        password: await bcrypt.hash('password123', 12),
        nickname: 'Test User',
        phone: '13800138002',
        status: 1,
      });
      await userRepository.save(testUser);
    });

    const updateUserDto = {
      nickname: 'Updated User',
      phone: '13800138003',
      status: 0,
    };

    it('should update user successfully', async () => {
      const response = await request(app.getHttpServer())
        .put(`/api/users/${testUser.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send(updateUserDto)
        .expect(200);

      expect(response.body).toMatchObject({
        id: testUser.id,
        username: testUser.username,
        nickname: updateUserDto.nickname,
        phone: updateUserDto.phone,
        status: updateUserDto.status,
      });
    });

    it('should return 404 when user not found', async () => {
      const response = await request(app.getHttpServer())
        .put('/api/users/999')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(updateUserDto)
        .expect(404);

      expect(response.body.message).toBe('用户不存在');
    });
  });

  describe('/api/users/:id (DELETE)', () => {
    let testUser: User;

    beforeEach(async () => {
      testUser = userRepository.create({
        username: 'testuser',
        email: 'test@example.com',
        password: await bcrypt.hash('password123', 12),
        nickname: 'Test User',
        phone: '13800138002',
        status: 1,
      });
      await userRepository.save(testUser);
    });

    it('should delete user successfully', async () => {
      await request(app.getHttpServer())
        .delete(`/api/users/${testUser.id}`)
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(200);

      // 验证用户已被删除
      const deletedUser = await userRepository.findOneBy({ id: testUser.id });
      expect(deletedUser).toBeNull();
    });

    it('should return 404 when user not found', async () => {
      const response = await request(app.getHttpServer())
        .delete('/api/users/999')
        .set('Authorization', `Bearer ${adminToken}`)
        .expect(404);

      expect(response.body.message).toBe('用户不存在');
    });
  });

  describe('/api/users/:id/roles (POST)', () => {
    let testUser: User;

    beforeEach(async () => {
      testUser = userRepository.create({
        username: 'testuser',
        email: 'test@example.com',
        password: await bcrypt.hash('password123', 12),
        nickname: 'Test User',
        phone: '13800138002',
        status: 1,
      });
      await userRepository.save(testUser);
    });

    it('should assign roles to user successfully', async () => {
      const assignRolesDto = {
        roleIds: [1, 2],
      };

      await request(app.getHttpServer())
        .post(`/api/users/${testUser.id}/roles`)
        .set('Authorization', `Bearer ${adminToken}`)
        .send(assignRolesDto)
        .expect(200);

      // 验证角色已分配
      const userWithRoles = await userRepository.findOne({
        where: { id: testUser.id },
        relations: ['userRoles'],
      });

      expect(userWithRoles.userRoles).toHaveLength(2);
    });

    it('should return 404 when user not found', async () => {
      const assignRolesDto = {
        roleIds: [1],
      };

      const response = await request(app.getHttpServer())
        .post('/api/users/999/roles')
        .set('Authorization', `Bearer ${adminToken}`)
        .send(assignRolesDto)
        .expect(404);

      expect(response.body.message).toBe('用户不存在');
    });
  });
});